/**
 * Copyright (c) 2009  Collaborative Development Group, C.S. Dept., University of Bari
 *
 * All rights reserved. This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0  which accompanies this distribution, and is 
 * available at http://www.eclipse.org/legal/epl-v10.html
 */
package it.uniba.di.cdg.penelope.ui.swt;

import it.uniba.di.cdg.penelope.ui.job.RunAsJob;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;

import com.google.inject.Provider;

/**
 * This aspect is an interceptor for executing methods annotated with {@link RunAsJob} using the Eclipse {@link Job} API.
 * TODO Support injection for this aspect!
 */
@Aspect
public abstract class AbstractSWTThreadingAspect {

//	@Inject
	private Provider<Display> displayProvider = new Provider<Display>() {
		@Override
		public Display get() {
	    	Display display = PlatformUI.getWorkbench().getDisplay();
	        if (display == null) { // Fallback
	            display = Display.getCurrent();
	        }
	        return display;		
		}
	};
	
//	@Inject 
//	private LogService logger;

	@Pointcut( "" )
	public abstract void scope();
	
	
	@Pointcut( "execution( @it.uniba.di.cdg.penelope.ui.swt.SWTAsyncExec void *(..)) && @annotation( ann )" )
	public void onAsynchMethod( SWTAsyncExec ann ) {}

	@Pointcut( "execution( @it.uniba.di.cdg.penelope.ui.swt.SWTSyncExec * *(..)) && @annotation( ann )" )
	public void onSynchMethod( SWTSyncExec ann ) {}
	
	@Around( "onAsynchMethod( ann )" )
	public final void executeAsynch( SWTAsyncExec ann, final ProceedingJoinPoint pjp ) {
		displayProvider.get().asyncExec( new Runnable() {
            public void run() {
                try {
                     pjp.proceed();
                } catch (Throwable e) {
//                	logger.log( LOG_ERROR, e.getMessage() );
                    throw new SWTThreadException( e );
                }
            }
        });
	}

	@Around( "onSynchMethod( ann )" )
	public final Object executeSynch( SWTSyncExec ann, final ProceedingJoinPoint pjp ) {
    	final SynchRunnable task = new SynchRunnable() {
            public void run() {
                try {
                	Object value = pjp.proceed();
                    setValue( /*invocation.proceed()*/ value );
                } catch (Throwable e) {
//                	logger.log( LOG_ERROR, e.getMessage() );
                    throw new SWTThreadException( e );
                }
            }
    	};
        displayProvider.get().syncExec( task );
        return task.getValue();		
	}
	
	/**
	 * Runnable that holds values that can be checked back after execution.
	 */
	private static abstract class SynchRunnable implements Runnable {
	    
		private Object value;

	    public Object getValue() {
	        return value;
	    }

	    public void setValue( Object value ) {
	        this.value = value;
	    }
	}
}
